/*
* @overview: 
* @Author: wgf 
* @Date: 2024-04-25 10:19:43 
*/

import 'package:flutter/material.dart';
import 'package:rc_widget/rc_widget.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';

import 'image_provider.dart';

enum ImageStatus {
  fail,
  loading,
  success,
}

class AppNetworkImage extends StatefulWidget {
  AppNetworkImage({
    super.key,
    required this.src,
    this.width,
    this.height,
    this.margin,
    this.radius,
    this.color,
    this.dimension,
    this.borderRadius,
    this.cacheWidth,
    this.cacheHeight,
    this.defaultImage = '',
    this.cache = false,
    this.fit = BoxFit.cover,
    this.shape = BoxShape.rectangle,
  }) : imageProvider = ResizeImage.resizeIfNeeded(
          cacheWidth,
          cacheHeight,
          AppImageProvider(
            url: src,
            cache: cache,
          ),
        );

  final String src;
  final BoxFit fit;
  final bool cache;
  final Color? color;
  final double? width;
  final double? height;
  final int? cacheWidth;
  final int? cacheHeight;
  final double? radius;
  final BoxShape shape;
  final double? dimension;
  final String defaultImage;

  final EdgeInsetsGeometry? margin;
  final ImageProvider imageProvider;
  final BorderRadiusGeometry? borderRadius;

  @override
  AppNetworkImageState createState() => AppNetworkImageState();
}

class AppNetworkImageState extends State<AppNetworkImage> {
  ImageStream? imageStream;
  ImageStatus imageStatus = ImageStatus.loading;

  late ImageStreamListener listener;
  late final DisposableBuildContext scrollAwareContext = DisposableBuildContext(this);

  double? get width => widget.dimension ?? widget.width;
  double? get height => widget.dimension ?? widget.height;

  Color? get background => widget.color ?? Colors.grey[300];

  @override
  void didChangeDependencies() {
    resolveImageStream();

    super.didChangeDependencies();
  }

  @override
  void didUpdateWidget(AppNetworkImage oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (widget.imageProvider != oldWidget.imageProvider) resolveImageStream();
  }

  @override
  void dispose() {
    imageStream?.removeListener(listener);
    super.dispose();
  }

  void resolveImageStream() {
    final ScrollAwareImageProvider provider = ScrollAwareImageProvider<Object>(
      context: scrollAwareContext,
      imageProvider: widget.imageProvider,
    );

    final ImageStream newStream = provider.resolve(createLocalImageConfiguration(
      context,
      size: widget.width != null && widget.height != null ? Size(widget.width!, widget.height!) : null,
    ));

    updateSourceStream(newStream);
  }

  void updateSourceStream(ImageStream newStream) {
    if (imageStream?.key == newStream.key) return;

    imageStatus = ImageStatus.loading;
    update();

    if (imageStream != null) {
      imageStream!.removeListener(getListener());
    }

    imageStream = newStream;
    imageStream!.addListener(getListener(recreateListener: true));
  }

  ImageStreamListener getListener({bool recreateListener = false}) {
    if (recreateListener) {
      listener = ImageStreamListener(
        onImage,
        onChunk: onChunk,
        onError: onError,
      );
    }

    return listener;
  }

  void onImage(ImageInfo imageInfo, bool s) {
    imageStatus = ImageStatus.success;
    update();
  }

  void onChunk(ImageChunkEvent chunkEvent) {}

  void onError(Object e, StackTrace? t) {
    imageStatus = ImageStatus.fail;
    update();
  }

  void update() {
    if (mounted) setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    late Widget child;

    switch (imageStatus) {
      case ImageStatus.fail:
        child = _buildError();
        break;

      case ImageStatus.loading:
        child = _buildLoading();
        break;

      default:
        child = _buildSuccess();
    }

    if (widget.borderRadius != null) {
      child = ClipRRect(
        borderRadius: widget.borderRadius!,
        child: child,
      );
    } else if (widget.radius != null) {
      child = ClipRRect(
        borderRadius: BorderRadius.circular(widget.radius!),
        child: child,
      );
    } else if (widget.shape == BoxShape.circle) {
      child = ClipOval(child: child);
    }

    if (widget.margin != null) {
      child = Padding(
        padding: widget.margin!,
        child: child,
      );
    }

    return child;
  }

  Widget _buildLoading() {
    return Container(
      alignment: Alignment.center,
      width: width,
      height: height,
      color: background,
      child: SpinKitCircle(
        size: 40.sp,
        color: Colors.pink,
      ),
    );
  }

  Widget _buildError() {
    if (widget.defaultImage.isNotEmpty) {
      return Image.asset(
        widget.defaultImage,
        width: width,
        height: height,
      );
    }

    return Container(
      alignment: Alignment.center,
      width: width,
      height: height,
      color: background,
      child: Icon(
        Icons.broken_image,
        size: 40.sp,
        color: Colors.red,
      ),
    );
  }

  Widget _buildSuccess() {
    return Image(
      width: width,
      height: height,
      fit: widget.fit,
      image: widget.imageProvider,
    );
  }
}
